﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GameUtils.Input;
using GMLogging;

namespace GameControls
{
    public sealed class Button : ControlBase
    {
        #region Constants
        private static readonly Color NORMAL_COLOR = Color.White;
        private static readonly Color OVER_COLOR = Color.Gray;
        private static readonly Color DOWN_COLOR = Color.Green;

        private const int MOUSE_ALPHA_THRESHOLD = 20;
        #endregion

        #region Properties
        #region Label
        /// <summary>
        /// Label property.
        /// </summary>
        public Label Label { get; private set; }
        #endregion

        #region Texture
        /// <summary>
        /// Texture property.
        /// </summary>
        public Texture2D Texture { get; private set; }
        #endregion

        private bool mIsMouseOver;
        private bool mIsButtonDown;
        #endregion

        #region Events
        #region Pressed
        public event EventHandler Pressed;

        private void RaisePressedEvent()
        {
            var handler = Pressed;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
        #endregion
        #endregion

        #region Constructors
        public Button(Rectangle pRect, Texture2D pTexture)
            : base(pRect)
        {
            Texture = pTexture;

            mIsMouseOver = false;
            mIsButtonDown = false;

            Rectangle labelRect = new Rectangle(0, 0, pRect.Width, pRect.Height);
            Label = new Label(labelRect);
            AddComponent(Label);
        }
        #endregion

        #region Overriden Methods
        protected override void Dispose(bool pDisposing)
        {
            if (pDisposing)
            {
                RemoveComponent(Label);
            }
        }

        protected override void UpdateImpl(GameTime pGameTime)
        {
        }

        #region Mouse
        protected override void OnLeftButtonDownImpl(MouseEventArgs pArgs)
        {
            mIsMouseOver = IsMouseOver(pArgs.X, pArgs.Y);
            mIsButtonDown = mIsMouseOver;
            if (mIsButtonDown)
            {
                MouseCapture.Capture(this);
            }
        }

        protected override void OnLeftButtonUpImpl(MouseEventArgs pArgs)
        {
            mIsMouseOver = IsMouseOver(pArgs.X, pArgs.Y);
            if (mIsMouseOver && mIsButtonDown)
            {
                RaisePressedEvent();
            }
            mIsButtonDown = false;
        }

        protected override void OnMouseMoveImpl(MouseEventArgs pArgs)
        {
            mIsMouseOver = IsMouseOver(pArgs.X, pArgs.Y);
        }
        #endregion
        #endregion

        #region Methods
        public Color GetColorForCurrentState()
        {
            return GetColorForState(mIsMouseOver, mIsButtonDown);
        }

        private static Color GetColorForState(bool isMouseOver, bool isButtonDown)
        {
            if (isMouseOver)
            {
                if (isButtonDown)
                {
                    return DOWN_COLOR;
                }
                else
                {
                    return OVER_COLOR;
                }
            }
            else
            {
                return NORMAL_COLOR;
            }
        }

        internal override bool IsMouseOver(int pMouseX, int pMouseY)
        {
            Rectangle transformedRect = TransformedRect;
            if (transformedRect.Contains(pMouseX, pMouseY))
            {
                int textureDataCount = Texture.Width * Texture.Height;
                int textureDataX = (pMouseX - transformedRect.X) * Texture.Width / transformedRect.Width;
                int textureDataY = (pMouseY - transformedRect.Y) * Texture.Height / transformedRect.Height;
                int textureDataIndex = textureDataX + textureDataY * Texture.Width;
                if (0 <= textureDataIndex && textureDataIndex < textureDataCount)
                {
                    uint[] textureData = new uint[textureDataCount];
                    Texture.GetData<uint>(textureData);
                    byte alpha = (byte)((textureData[textureDataIndex] & 0xff000000) >> 24);

                    bool isOverThis = alpha > MOUSE_ALPHA_THRESHOLD;
                    if (Parent != null)
                    {
                        return isOverThis && Parent.IsMouseOver(pMouseX, pMouseY);
                    }
                    else
                    {
                        return isOverThis;
                    }
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        #endregion
    }
}